package cn.zniot.so.transport.server;

import cn.zniot.so.application.SessionManager;
import cn.zniot.so.application.constant.Constants;
import cn.zniot.so.application.data.Session;
import cn.zniot.so.application.util.MethodUtil;
import cn.zniot.so.application.util.PropertyUtil;
import cn.zniot.so.transport.asynpack.AsynPacket;
import cn.zniot.so.transport.asynpack.LogicCotrolPacketD;
import cn.zniot.so.transport.asynpack.PacketType;
import cn.zniot.so.transport.asynpack.Zniot2ControlPacketD;
import cn.zniot.so.transport.asynpack.Zniot2PacketC;

import org.apache.log4j.Logger;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

/**
 * TCP服务端业务逻辑处理器
 */
public class BoxAndClientServerHandler extends IoHandlerAdapter {
	private static Logger logger = Logger.getLogger(BoxAndClientServerHandler.class);
	private String ipAndPort;
	private Zniot2PacketC packet = null;
	// 登录
	private final static int LOGIN = 0x42;
	// 交互
	private final static int INTERACTIVE = 0x54;
	// 操作成功
	private final static int OPT_SUCCESS = 0x4F;
	// 操作失败
	private final static int OPT_FAIL = 0x52;

	@Override
	public void sessionOpened(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		super.sessionOpened(session);
		session.getConfig().setBothIdleTime(1800);// set timeout seconds, must
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		// TODO Auto-generated method stub
		super.sessionCreated(session);
		// 给客户端发送一个连接的通知
		if (packet == null) {
			packet = new Zniot2PacketC();
		}
		packet.setCode(Constants.TRYLINK);
		session.write(packet);
	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
		// TODO Auto-generated method stub
		super.sessionIdle(session, status);
		session.close(true);// timeout now, close it
		if (logger.isDebugEnabled()) {
			logger.debug("session timeout now, close it!");
		}
	}

	@Override
	public void messageReceived(IoSession session, Object message) throws Exception {
		//TODO  注意把心跳包给排除掉后才能进行下面的操作
		// ====================================================
		byte[] msg = (byte[]) message;
		int cmdHeader = msg[0];
		switch (cmdHeader) {
		case LOGIN:
			// TODO 调用你的业务方法吧
			break;
		case INTERACTIVE:

			break;
		case OPT_SUCCESS:

			break;
		case OPT_FAIL:

			break;

		default:
			break;
		}
		// 用于确认业务已经处理完成
		System.out.println("complete.....................................");
		// ====================================================
		ipAndPort = session.getRemoteAddress().toString();
		AsynPacket packet = (AsynPacket) message;
		if (packet.getPackType().equals(PacketType.Zniot2)) {
			// ControlSyncManager.getInstance().setMessages(ipAndPort, new
			// String(((Zniot2ControlPacketD) packet).getbyteCode(), "UTF-8"));
			// if (logger.isDebugEnabled()) {
			// logger.debug("Zniot2PacketD length:" + ((Zniot2ControlPacketD)
			// packet).getbyteCode().length);
			// }
			int length = ((Zniot2ControlPacketD) packet).getbyteCode().length;
			if (length == 12) {
				ipChanage(packet, Constants.FAIL_CONNECT, Constants.BOXRATE, Constants.NO_DATA);
			} else if (length == 7) {
				ipChanage(packet, Constants.SLEEP_SEND_COMMAND, Constants.NO_DATA, Constants.BOXRATE);
			}

		} else if (packet.getPackType().equals(PacketType.LOGIC_D)) {
			// 逻辑控制报文
			LogicCotrolPacketD p = (LogicCotrolPacketD) packet;
			String type = p.getType();
			p.setUid(ipAndPort);
			p.setPdString(Constants.SINGE_YES);
			if (type.equalsIgnoreCase("AI")) {
				String imei = p.getImei();
				String desc = p.getData2();
				if (imei != null) {
					// Zniot每次连接后主动上报密码和IMEI
					putMemoryAndDb(session, p, imei, desc);
				}
			}
		}
	}

	private void ipChanage(AsynPacket packet, String sign, String box, String mobile) {
		String imeiByIpPort = PropertyUtil.getInstance().getIMEIByIpPort(ipAndPort);
		if (imeiByIpPort != null) {
			imeiByIpPort = sign + imeiByIpPort.substring(1);
			IoSession boxIoSession = Session.getBoxIoSession(imeiByIpPort);
			if (boxIoSession == null) {
				writeErrMsg(box, mobile);
			} else {
				boxIoSession.write(((Zniot2ControlPacketD) packet));
			}
		} else {
			writeErrMsg(box, mobile);
		}
	}

	private void writeErrMsg(String box, String mobile) {
		logger.error("根据传入" + box + "的ID未获取到" + mobile + "与服务器通信session!");
	}

	private void putMemoryAndDb(IoSession session, LogicCotrolPacketD p, String imei, String desc) {
		if (logger.isInfoEnabled()) {
			if (desc.equals(Constants.ID_HEAD)) {
				desc = Constants.NO_DATA;
			} else {
				desc = Constants.BOXRATE;
			}
			logger.info(desc + "(" + imei + ")上线了!" + ipAndPort);
		}
		login(session, imei);// 盒子登录处理
		try {
			Session.tcpQueue.offer(p);
			// 将下边的线程操作移除，重新在非mina线程的地方做这个操作
		} catch (Exception ex) {
			// 写入队列错误
			logger.error("写入队列错误--" + ex);
		}
	}

	/**
	 * 盒子登录
	 */
	private void login(IoSession session, String imei) {
		if (session != null) {
			SessionManager.getInstance().register_tcp(ipAndPort, session);// 保存Zniot客户端的session引用
			PropertyUtil.getInstance().addIpPortToIMEI(ipAndPort, imei);// 添加临时IP&Port与IMEI号的映射
		}
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("tcp session closed--" + session.getId());
		}
		// 给客户端发送通知这个会话结束了
		String ipAndPort = SessionManager.getInstance().getIpPortByIosession(session);
		if (ipAndPort != null && ipAndPort.startsWith(Constants.FAIL_CONNECT)) {
			Session.sendLeaveMessage(ipAndPort);
		}
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		logger.error(MethodUtil.printExceptionErr(cause));
		session.close(true);// timeout now, close it
	}

}
